#define OUTPUT_FILE_NAME "platform_info.hpp"
#define MACRO_PREFIX "STX_"

#include <limits.h>
#include <fstream>
#include <string>
#include <cctype>
#include <cfloat>
using namespace std;

inline string to_upper(const string& s)
{
    string ret(s);
    for (size_t i = 0; i < ret.size(); ++i) {
        ret[i] = toupper(ret[i]);
    }
    return ret;
}

#define WRITE(name, value) \
    write(to_upper(#name), value);

struct platform_info
{
    void init()
    {
        if (initialized_) {
            return;
        }
        initialized_ = true;
    }
    
    platform_info()
    {
        init();
    }
    
    void write_to_file(const string& file_name)
    {
        init();
        file_.exceptions(ifstream::eofbit | ifstream::failbit | ifstream::badbit);
        file_.open(file_name.c_str(), ios_base::out | ios_base::binary);
        file_ << "#ifndef " << header_guard() << "\n"
            << "#define " << header_guard() << "\n\n";
        
        
        
        file_ << "#endif // " << header_guard() << "\n";
    }
    
    ~platform_info()
    {
        
    }
    
    template<class T>
    void write(const string& base_name, const T& value)
    {
        string name = MACRO_PREFIX + base_name;
        file_ << "#ifndef " << name << "\n"
            << "#define " << name << " " << value << "\n"
            << "#endif" << "\n\n";
    }
    
    string header_guard()
    {
        return "STX_PLATFORM_INFO_HPP";
    }
    
    bool initialized_;
    ofstream file_;
    
    bool
        has_float,
        has_double,
        has_long_double,
        has_long_long,
        has_wchar_t,
        has_char16_t,
        has_char32_t;
    
    size_t
        sizeof_void_ptr,
        sizeof_char,
        sizeof_short,
        sizeof_int,
        sizeof_long,
        sizeof_float,
        sizeof_double,
        sizeof_long_double,
        sizeof_long_long,
        sizeof_wchar_t,
        sizeof_char16_t,
        sizeof_char32_t,
        char_bits,
        short_bits,
        int_bits,
        long_bits,
        float_bits,
        double_bits,
        long_double_bits,
        long_long_bits,
        wchar_t_bits,
        char16_t_bits,
        char32_bits;
};

int main(int argc, char** argv)
{
    using namespace std;
    platform_info w(OUTPUT_FILE_NAME);
    w.write("SIZEOF_CHAR", (int) sizeof(char));
    return 0;
}
